#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
数据库连接和会话管理

这个模块负责：
1. 数据库引擎创建和配置
2. 数据库会话管理
3. 数据库表创建和初始化
4. 依赖注入支持

支持的数据库：
- SQLite（默认，用于开发和测试）
- PostgreSQL（推荐用于生产环境）
- MySQL（可选支持）

作者: FastAPI 学习项目
创建时间: 2024
"""

import os
from typing import Generator
from sqlalchemy import create_engine, MetaData, text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from sqlalchemy.pool import StaticPool
from loguru import logger

from config import settings

# 创建数据库引擎
if settings.DATABASE_URL.startswith("sqlite"):
    # SQLite 配置
    engine = create_engine(
        settings.DATABASE_URL,
        connect_args={
            "check_same_thread": False,  # SQLite 特定配置
            "timeout": 20  # 连接超时时间
        },
        poolclass=StaticPool,  # SQLite 使用静态连接池
        echo=settings.DATABASE_ECHO,  # 是否打印 SQL 语句
        future=True  # 使用 SQLAlchemy 2.0 风格
    )
else:
    # PostgreSQL/MySQL 配置
    engine = create_engine(
        settings.get_database_url(),
        pool_size=10,  # 连接池大小
        max_overflow=20,  # 最大溢出连接数
        pool_pre_ping=True,  # 连接前检查
        pool_recycle=3600,  # 连接回收时间（秒）
        echo=settings.DATABASE_ECHO,
        future=True
    )

# 创建会话工厂
SessionLocal = sessionmaker(
    autocommit=False,
    autoflush=False,
    bind=engine,
    future=True
)

# 创建基础模型类
Base = declarative_base()

# 元数据对象，用于表操作
metadata = MetaData()


def get_db() -> Generator[Session, None, None]:
    """
    获取数据库会话
    
    这是一个依赖注入函数，用于 FastAPI 的 Depends
    自动管理数据库会话的生命周期
    
    Yields:
        Session: 数据库会话对象
        
    Example:
        ```python
        @app.get("/users/")
        async def get_users(db: Session = Depends(get_db)):
            return crud.get_users(db)
        ```
    """
    db = SessionLocal()
    try:
        yield db
    except Exception as e:
        logger.error(f"数据库会话错误: {e}")
        db.rollback()
        raise
    finally:
        db.close()


async def init_db() -> None:
    """
    初始化数据库
    
    执行以下操作：
    1. 创建数据库表
    2. 创建必要的目录
    3. 初始化基础数据
    
    这个函数在应用启动时调用
    """
    try:
        logger.info("开始初始化数据库...")
        
        # 确保数据库目录存在（SQLite）
        if settings.DATABASE_URL.startswith("sqlite"):
            db_path = settings.DATABASE_URL.replace("sqlite:///", "")
            db_dir = os.path.dirname(db_path)
            if db_dir and not os.path.exists(db_dir):
                os.makedirs(db_dir)
                logger.info(f"创建数据库目录: {db_dir}")
        
        # 创建所有表
        await create_tables()
        
        # 创建初始数据
        await create_initial_data()
        
        logger.success("数据库初始化完成")
        
    except Exception as e:
        logger.error(f"数据库初始化失败: {e}")
        raise


async def create_tables() -> None:
    """
    创建数据库表
    
    根据模型定义创建所有数据库表
    如果表已存在则跳过
    """
    try:
        # 导入所有模型以确保它们被注册
        from app.models.user import User
        from app.models.item import Item
        
        # 创建所有表
        Base.metadata.create_all(bind=engine)
        logger.info("数据库表创建完成")
        
    except Exception as e:
        logger.error(f"创建数据库表失败: {e}")
        raise


async def drop_tables() -> None:
    """
    删除所有数据库表
    
    警告：这将删除所有数据！
    仅用于开发和测试环境
    """
    try:
        Base.metadata.drop_all(bind=engine)
        logger.warning("所有数据库表已删除")
        
    except Exception as e:
        logger.error(f"删除数据库表失败: {e}")
        raise


async def create_initial_data() -> None:
    """
    创建初始数据
    
    创建系统必需的初始数据，如：
    1. 管理员用户
    2. 默认分类
    3. 系统配置
    """
    try:
        from app.models.user import User
        from app.utils.security import get_password_hash
        
        db = SessionLocal()
        
        try:
            # 检查是否已有管理员用户
            admin_user = db.query(User).filter(
                User.username == "admin"
            ).first()
            
            if not admin_user:
                # 创建管理员用户
                admin_user = User(
                    username="admin",
                    email="admin@example.com",
                    hashed_password=get_password_hash("admin123456"),
                    full_name="系统管理员",
                    is_active=True,
                    is_superuser=True,
                    bio="系统默认管理员账户"
                )
                db.add(admin_user)
                db.commit()
                logger.info("创建默认管理员用户: admin / admin123456")
            
            # 创建测试用户
            test_user = db.query(User).filter(
                User.username == "testuser"
            ).first()
            
            if not test_user:
                test_user = User(
                    username="testuser",
                    email="test@example.com",
                    hashed_password=get_password_hash("test123456"),
                    full_name="测试用户",
                    is_active=True,
                    is_superuser=False,
                    bio="系统测试用户"
                )
                db.add(test_user)
                db.commit()
                logger.info("创建测试用户: testuser / test123456")
            
            logger.info("初始数据创建完成")
            
        except Exception as e:
            db.rollback()
            logger.error(f"创建初始数据失败: {e}")
            raise
        finally:
            db.close()
            
    except Exception as e:
        logger.error(f"初始数据创建过程失败: {e}")
        raise


async def check_db_connection() -> bool:
    """
    检查数据库连接
    
    测试数据库连接是否正常
    
    Returns:
        bool: 连接是否成功
    """
    try:
        db = SessionLocal()
        # 执行简单查询测试连接
        db.execute(text("SELECT 1"))
        db.close()
        logger.info("数据库连接正常")
        return True
    except Exception as e:
        logger.error(f"数据库连接失败: {e}")
        return False


async def get_db_info() -> dict:
    """
    获取数据库信息
    
    Returns:
        dict: 包含数据库信息的字典
    """
    try:
        db = SessionLocal()
        
        # 获取数据库版本等信息
        if settings.DATABASE_URL.startswith("sqlite"):
            result = db.execute(text("SELECT sqlite_version()"))
            version = result.scalar()
            db_type = "SQLite"
        elif settings.DATABASE_URL.startswith("postgresql"):
            result = db.execute(text("SELECT version()"))
            version = result.scalar()
            db_type = "PostgreSQL"
        else:
            version = "Unknown"
            db_type = "Unknown"
        
        db.close()
        
        return {
            "type": db_type,
            "version": version,
            "url": settings.DATABASE_URL,
            "echo": settings.DATABASE_ECHO
        }
        
    except Exception as e:
        logger.error(f"获取数据库信息失败: {e}")
        return {
            "type": "Unknown",
            "version": "Unknown",
            "url": settings.DATABASE_URL,
            "echo": settings.DATABASE_ECHO,
            "error": str(e)
        }


class DatabaseManager:
    """
    数据库管理器类
    
    提供数据库管理的高级接口
    """
    
    def __init__(self):
        self.engine = engine
        self.session_factory = SessionLocal
    
    def create_session(self) -> Session:
        """
        创建新的数据库会话
        
        Returns:
            Session: 数据库会话对象
        """
        return self.session_factory()
    
    def execute_raw_sql(self, sql: str, params: dict = None) -> any:
        """
        执行原生 SQL 语句
        
        Args:
            sql: SQL 语句
            params: 参数字典
            
        Returns:
            查询结果
        """
        db = self.create_session()
        try:
            if params:
                result = db.execute(sql, params)
            else:
                result = db.execute(sql)
            db.commit()
            return result
        except Exception as e:
            db.rollback()
            logger.error(f"执行 SQL 失败: {e}")
            raise
        finally:
            db.close()
    
    def backup_database(self, backup_path: str) -> bool:
        """
        备份数据库
        
        Args:
            backup_path: 备份文件路径
            
        Returns:
            bool: 备份是否成功
        """
        try:
            if settings.DATABASE_URL.startswith("sqlite"):
                import shutil
                db_path = settings.DATABASE_URL.replace("sqlite:///", "")
                shutil.copy2(db_path, backup_path)
                logger.info(f"数据库备份完成: {backup_path}")
                return True
            else:
                logger.warning("当前数据库类型不支持自动备份")
                return False
        except Exception as e:
            logger.error(f"数据库备份失败: {e}")
            return False


# 创建全局数据库管理器实例
db_manager = DatabaseManager()


# 导出主要组件
__all__ = [
    "Base",
    "engine",
    "SessionLocal",
    "get_db",
    "init_db",
    "create_tables",
    "drop_tables",
    "create_initial_data",
    "check_db_connection",
    "get_db_info",
    "DatabaseManager",
    "db_manager"
]